/************************************************************************
Copyright (c) 2010, 2013, C.R. All rights reserved. 

E-mail: crtoyou@gmail.com; crtoyou@163.com

You can redistribute it and/or modify it under the terms of the
GNU Lesser General Public License as published by the
Free Software Foundation version 3 of the License.

This source code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. if not, write to the Free Software Foundation, Inc., 
51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
************************************************************************/

#ifndef __CR_DEBUG_OUTPUT_H_
#define __CR_DEBUG_OUTPUT_H_

#include <tchar.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <malloc.h>
#include <Windows.h>
#pragma comment(lib, "User32.lib")

inline bool CR_PromptW(const wchar_t format[], ... )
{
	va_list arglist;
	va_start(arglist, format);
	int len = _vscwprintf(format, arglist) + 1; // include "\0"
	wchar_t* str = (wchar_t*)malloc(len*sizeof(wchar_t)); if(!str) abort();
	vswprintf_s(str, len, format, arglist);
	int ret = MessageBoxW(0, str, L"Debug Prompt", MB_ABORTRETRYIGNORE);
	free(str);
	if (IDIGNORE == ret) return true;
	else if (IDABORT == ret) exit(-1);
	return false;
}
inline bool CR_PromptA(const char format[], ... )
{
	va_list arglist;
	va_start(arglist, format);
	int len = _vscprintf(format, arglist) + 1; // include "\0"
	char* str = (char*)malloc(len*sizeof(char)); if(!str) abort();
	vsprintf_s(str, len, format, arglist);
	int ret = MessageBoxA(0, str, "Debug Prompt", MB_ABORTRETRYIGNORE);
	free(str);
	if (IDIGNORE == ret) return true;
	else if (IDABORT == ret) exit(-1);
	return false;
}

#ifdef _UNICODE
#define CR_Prompt CR_PromptW
#else //!_UNICODE
#define CR_Prompt CR_PromptA
#endif //_UNICODE

#ifdef _DEBUG
#define CR_PROMPT CR_Prompt
#define CR_PROMPTA CR_PromptA
#define CR_PROMPTW CR_PromptW
#else   // !_DEBUG
#define CR_PROMPT __noop
#define CR_PROMPTA __noop
#define CR_PROMPTW __noop
#endif // _DEBUG


inline void CR_TraceW(const wchar_t format[], ...)
{
	va_list arglist;
	va_start(arglist, format);
	int len = _vscwprintf_l(format, NULL, arglist) + 1; // include "\0"
	wchar_t* str = (wchar_t*)malloc(len*sizeof(wchar_t)); if(!str) abort();
	_vswprintf_s_l(str, len, format, NULL, arglist);
	OutputDebugStringW(str);
	free(str);
}
inline void CR_TraceA(const char format[], ...)
{
	va_list arglist;
	va_start(arglist, format);
	int len = _vscprintf_l(format, NULL, arglist) + 1; // include "\0"
	char* str = (char*)malloc(len*sizeof(char)); if(!str) abort();
	_vsprintf_s_l(str, len, format, NULL, arglist);
	OutputDebugStringA(str);
	free(str);
}

#ifdef _UNICODE
#define CR_Trace CR_TraceW
#else //!_UNICODE
#define CR_Trace CR_TraceA
#endif //_UNICODE

#ifdef _DEBUG
#define CR_TRACE CR_Trace
#define CR_TRACEA CR_TraceA
#define CR_TRACEW CR_TraceW
#else // !_DEBUG
#define CR_TRACE  __noop
#define CR_TRACEA  __noop
#define CR_TRACEW  __noop
#endif // _DEBUG


#define CR_Assert(X)  if(!(X))DebugBreak()
#ifdef _DEBUG
#define CR_ASSERT(X) CR_Assert(X)
#define CR_VERIFY(X) CR_Assert(X)
#else // !_DEBUG 
#define CR_ASSERT(X) __noop
#define CR_VERIFY(X) (X)
#endif // _DEBUG 


#ifdef _DEBUG
#define CR_DEBUGING(X) (X)
#else // !_DEBUG 
#define CR_DEBUGING(X) __noop
#endif // _DEBUG 


#ifndef PROMPT
#define PROMPT CR_PROMPT
#define PROMPTA CR_PROMPTA
#define PROMPTW CR_PROMPTW
#endif
#ifndef TRACE
#define TRACE CR_TRACE
#define TRACEA CR_TRACEA
#define TRACEW CR_TRACEW
#endif
#ifndef VERIFY
#define VERIFY CR_VERIFY
#endif
#ifndef ASSERT
#define ASSERT CR_ASSERT
#endif
#ifndef DEBUGING
#define DEBUGING CR_DEBUGING
#endif

inline LPCTSTR DebugWmString(UINT msgCode)
{
	static LPCTSTR wm[0x0400] = {NULL};
	static BOOL binit = FALSE;
	if (!binit) 
	{
		wm[0x0000] = _T("WM_NULL");
		wm[0x0001] = _T("WM_CREATE");
		wm[0x0002] = _T("WM_DESTROY");
		wm[0x0003] = _T("WM_MOVE");
		wm[0x0005] = _T("WM_SIZE");
		wm[0x0006] = _T("WM_ACTIVATE");
		wm[0x0007] = _T("WM_SETFOCUS");
		wm[0x0008] = _T("WM_KILLFOCUS");
		wm[0x000A] = _T("WM_ENABLE");
		wm[0x000B] = _T("WM_SETREDRAW");
		wm[0x000C] = _T("WM_SETTEXT");
		wm[0x000D] = _T("WM_GETTEXT");
		wm[0x000E] = _T("WM_GETTEXTLENGTH");
		wm[0x000F] = _T("WM_PAINT");
		wm[0x0010] = _T("WM_CLOSE");
		wm[0x0011] = _T("WM_QUERYENDSESSION");
		wm[0x0012] = _T("WM_QUIT");
		wm[0x0013] = _T("WM_QUERYOPEN");
		wm[0x0014] = _T("WM_ERASEBKGND");
		wm[0x0015] = _T("WM_SYSCOLORCHANGE");
		wm[0x0016] = _T("WM_ENDSESSION");
		wm[0x0018] = _T("WM_SHOWWINDOW");
		wm[0x0019] = _T("WM_CTLCOLOR");
		wm[0x001A] = _T("WM_WININICHANGE=WM_SETTINGCHANGE");
		wm[0x001B] = _T("WM_DEVMODECHANGE");
		wm[0x001C] = _T("WM_ACTIVATEAPP");
		wm[0x001D] = _T("WM_FONTCHANGE");
		wm[0x001E] = _T("WM_TIMECHANGE");
		wm[0x001F] = _T("WM_CANCELMODE");
		wm[0x0020] = _T("WM_SETCURSOR");
		wm[0x0021] = _T("WM_MOUSEACTIVATE");
		wm[0x0022] = _T("WM_CHILDACTIVATE");
		wm[0x0023] = _T("WM_QUEUESYNC");
		wm[0x0024] = _T("WM_GETMINMAXINFO");
		wm[0x0026] = _T("WM_PAINTICON");
		wm[0x0027] = _T("WM_ICONERASEBKGND");
		wm[0x0028] = _T("WM_NEXTDLGCTL");
		wm[0x002A] = _T("WM_SPOOLERSTATUS");
		wm[0x002B] = _T("WM_DRAWITEM");
		wm[0x002C] = _T("WM_MEASUREITEM");
		wm[0x002D] = _T("WM_DELETEITEM");
		wm[0x002E] = _T("WM_VKEYTOITEM");
		wm[0x002F] = _T("WM_CHARTOITEM");
		wm[0x0030] = _T("WM_SETFONT");
		wm[0x0031] = _T("WM_GETFONT");
		wm[0x0032] = _T("WM_SETHOTKEY");
		wm[0x0033] = _T("WM_GETHOTKEY");
		wm[0x0037] = _T("WM_QUERYDRAGICON");
		wm[0x0039] = _T("WM_COMPAREITEM");
		wm[0x003D] = _T("WM_GETOBJECT");
		wm[0x0041] = _T("WM_COMPACTING");
		wm[0x0044] = _T("WM_COMMNOTIFY/*no longer suported*/");
		wm[0x0046] = _T("WM_WINDOWPOSCHANGING");
		wm[0x0047] = _T("WM_WINDOWPOSCHANGED");
		wm[0x0048] = _T("WM_POWER");
		wm[0x004A] = _T("WM_COPYDATA");
		wm[0x004B] = _T("WM_CANCELJOURNAL");
		wm[0x004E] = _T("WM_NOTIFY");
		wm[0x0050] = _T("WM_INPUTLANGCHANGEREQUEST");
		wm[0x0051] = _T("WM_INPUTLANGCHANGE");
		wm[0x0052] = _T("WM_TCARD");
		wm[0x0053] = _T("WM_HELP");
		wm[0x0054] = _T("WM_USERCHANGED");
		wm[0x0055] = _T("WM_NOTIFYFORMAT");
		wm[0x007B] = _T("WM_CONTEXTMENU");
		wm[0x007C] = _T("WM_STYLECHANGING");
		wm[0x007D] = _T("WM_STYLECHANGED");
		wm[0x007E] = _T("WM_DISPLAYCHANGE");
		wm[0x007F] = _T("WM_GETICON");
		wm[0x0080] = _T("WM_SETICON");
		wm[0x0081] = _T("WM_NCCREATE");
		wm[0x0082] = _T("WM_NCDESTROY");
		wm[0x0083] = _T("WM_NCCALCSIZE");
		wm[0x0084] = _T("WM_NCHITTEST");
		wm[0x0085] = _T("WM_NCPAINT");
		wm[0x0086] = _T("WM_NCACTIVATE");
		wm[0x0087] = _T("WM_GETDLGCODE");
		wm[0x0088] = _T("WM_SYNCPAINT");
		wm[0x00A0] = _T("WM_NCMOUSEMOVE");
		wm[0x00A1] = _T("WM_NCLBUTTONDOWN");
		wm[0x00A2] = _T("WM_NCLBUTTONUP");
		wm[0x00A3] = _T("WM_NCLBUTTONDBLCLK");
		wm[0x00A4] = _T("WM_NCRBUTTONDOWN");
		wm[0x00A5] = _T("WM_NCRBUTTONUP");
		wm[0x00A6] = _T("WM_NCRBUTTONDBLCLK");
		wm[0x00A7] = _T("WM_NCMBUTTONDOWN");
		wm[0x00A8] = _T("WM_NCMBUTTONUP");
		wm[0x00A9] = _T("WM_NCMBUTTONDBLCLK");
		wm[0x00AB] = _T("WM_NCXBUTTONDOWN");
		wm[0x00AC] = _T("WM_NCXBUTTONUP");
		wm[0x00AD] = _T("WM_NCXBUTTONDBLCLK");
		wm[0x00FE] = _T("WM_INPUT_DEVICE_CHANGE");
		wm[0x00FF] = _T("WM_INPUT");
		wm[0x0100] = _T("WM_KEYDOWN");
		wm[0x0101] = _T("WM_KEYUP");
		wm[0x0102] = _T("WM_CHAR");
		wm[0x0103] = _T("WM_DEADCHAR");
		wm[0x0104] = _T("WM_SYSKEYDOWN");
		wm[0x0105] = _T("WM_SYSKEYUP");
		wm[0x0106] = _T("WM_SYSCHAR");
		wm[0x0107] = _T("WM_SYSDEADCHAR");
		wm[0x0109] = _T("WM_UNICHAR");
		wm[0x010D] = _T("WM_IME_STARTCOMPOSITION");
		wm[0x010E] = _T("WM_IME_ENDCOMPOSITION");
		wm[0x010F] = _T("WM_IME_COMPOSITION");
		wm[0x0110] = _T("WM_INITDIALOG");
		wm[0x0111] = _T("WM_COMMAND");
		wm[0x0112] = _T("WM_SYSCOMMAND");
		wm[0x0113] = _T("WM_TIMER");
		wm[0x0114] = _T("WM_HSCROLL");
		wm[0x0115] = _T("WM_VSCROLL");
		wm[0x0116] = _T("WM_INITMENU");
		wm[0x0117] = _T("WM_INITMENUPOPUP");
		wm[0x011F] = _T("WM_MENUSELECT");
		wm[0x0120] = _T("WM_MENUCHAR");
		wm[0x0121] = _T("WM_ENTERIDLE");
		wm[0x0122] = _T("WM_MENURBUTTONUP");
		wm[0x0123] = _T("WM_MENUDRAG");
		wm[0x0124] = _T("WM_MENUGETOBJECT");
		wm[0x0125] = _T("WM_UNINITMENUPOPUP");
		wm[0x0126] = _T("WM_MENUCOMMAND");
		wm[0x0127] = _T("WM_CHANGEUISTATE");
		wm[0x0128] = _T("WM_UPDATEUISTATE");
		wm[0x0129] = _T("WM_QUERYUISTATE");
		wm[0x0132] = _T("WM_CTLCOLORMSGBOX");
		wm[0x0133] = _T("WM_CTLCOLOREDIT");
		wm[0x0134] = _T("WM_CTLCOLORLISTBOX");
		wm[0x0135] = _T("WM_CTLCOLORBTN");
		wm[0x0136] = _T("WM_CTLCOLORDLG");
		wm[0x0137] = _T("WM_CTLCOLORSCROLLBAR");
		wm[0x0138] = _T("WM_CTLCOLORSTATIC");
		wm[0x0200] = _T("WM_MOUSEMOVE");
		wm[0x0201] = _T("WM_LBUTTONDOWN");
		wm[0x0202] = _T("WM_LBUTTONUP");
		wm[0x0203] = _T("WM_LBUTTONDBLCLK");
		wm[0x0204] = _T("WM_RBUTTONDOWN");
		wm[0x0205] = _T("WM_RBUTTONUP");
		wm[0x0206] = _T("WM_RBUTTONDBLCLK");
		wm[0x0207] = _T("WM_MBUTTONDOWN");
		wm[0x0208] = _T("WM_MBUTTONUP");
		wm[0x0209] = _T("WM_MBUTTONDBLCLK");
		wm[0x020A] = _T("WM_MOUSEWHEEL");
		wm[0x020B] = _T("WM_XBUTTONDOWN");
		wm[0x020C] = _T("WM_XBUTTONUP");
		wm[0x020D] = _T("WM_XBUTTONDBLCLK");
		wm[0x020E] = _T("WM_MOUSEHWHEEL");
		wm[0x0210] = _T("WM_PARENTNOTIFY");
		wm[0x0211] = _T("WM_ENTERMENULOOP");
		wm[0x0212] = _T("WM_EXITMENULOOP");
		wm[0x0213] = _T("WM_NEXTMENU");
		wm[0x0214] = _T("WM_SIZING");
		wm[0x0215] = _T("WM_CAPTURECHANGED");
		wm[0x0216] = _T("WM_MOVING");
		wm[0x0218] = _T("WM_POWERBROADCAST");
		wm[0x0219] = _T("WM_DEVICECHANGE");
		wm[0x0220] = _T("WM_MDICREATE");
		wm[0x0221] = _T("WM_MDIDESTROY");
		wm[0x0222] = _T("WM_MDIACTIVATE");
		wm[0x0223] = _T("WM_MDIRESTORE");
		wm[0x0224] = _T("WM_MDINEXT");
		wm[0x0225] = _T("WM_MDIMAXIMIZE");
		wm[0x0226] = _T("WM_MDITILE");
		wm[0x0227] = _T("WM_MDICASCADE");
		wm[0x0228] = _T("WM_MDIICONARRANGE");
		wm[0x0229] = _T("WM_MDIGETACTIVE");
		wm[0x0230] = _T("WM_MDISETMENU");
		wm[0x0231] = _T("WM_ENTERSIZEMOVE");
		wm[0x0232] = _T("WM_EXITSIZEMOVE");
		wm[0x0233] = _T("WM_DROPFILES");
		wm[0x0234] = _T("WM_MDIREFRESHMENU");
		wm[0x0281] = _T("WM_IME_SETCONTEXT");
		wm[0x0282] = _T("WM_IME_NOTIFY");
		wm[0x0283] = _T("WM_IME_CONTROL");
		wm[0x0284] = _T("WM_IME_COMPOSITIONFULL");
		wm[0x0285] = _T("WM_IME_SELECT");
		wm[0x0286] = _T("WM_IME_CHAR");
		wm[0x0288] = _T("WM_IME_REQUEST");
		wm[0x0290] = _T("WM_IME_KEYDOWN");
		wm[0x0291] = _T("WM_IME_KEYUP");
		wm[0x02A0] = _T("WM_NCMOUSEHOVER");
		wm[0x02A1] = _T("WM_MOUSEHOVER");
		wm[0x02A2] = _T("WM_NCMOUSELEAVE");
		wm[0x02A3] = _T("WM_MOUSELEAVE");
		wm[0x02B1] = _T("WM_WTSSESSION_CHANGE");
		wm[0x02c0] = _T("WM_TABLET_FIRST");
		wm[0x02df] = _T("WM_TABLET_LAST");
		wm[0x0300] = _T("WM_CUT");
		wm[0x0301] = _T("WM_COPY");
		wm[0x0302] = _T("WM_PASTE");
		wm[0x0303] = _T("WM_CLEAR");
		wm[0x0304] = _T("WM_UNDO");
		wm[0x0305] = _T("WM_RENDERFORMAT");
		wm[0x0306] = _T("WM_RENDERALLFORMATS");
		wm[0x0307] = _T("WM_DESTROYCLIPBOARD");
		wm[0x0308] = _T("WM_DRAWCLIPBOARD");
		wm[0x0309] = _T("WM_PAINTCLIPBOARD");
		wm[0x030A] = _T("WM_VSCROLLCLIPBOARD");
		wm[0x030B] = _T("WM_SIZECLIPBOARD");
		wm[0x030C] = _T("WM_ASKCBFORMATNAME");
		wm[0x030D] = _T("WM_CHANGECBCHAIN");
		wm[0x030E] = _T("WM_HSCROLLCLIPBOARD");
		wm[0x030F] = _T("WM_QUERYNEWPALETTE");
		wm[0x0310] = _T("WM_PALETTEISCHANGING");
		wm[0x0311] = _T("WM_PALETTECHANGED");
		wm[0x0312] = _T("WM_HOTKEY");
		wm[0x0317] = _T("WM_PRINT");
		wm[0x0318] = _T("WM_PRINTCLIENT");
		wm[0x0319] = _T("WM_APPCOMMAND");
		wm[0x031A] = _T("WM_THEMECHANGED");
		wm[0x031D] = _T("WM_CLIPBOARDUPDATE");
		wm[0x031E] = _T("WM_DWMCOMPOSITIONCHANGED");
		wm[0x031F] = _T("WM_DWMNCRENDERINGCHANGED");
		wm[0x0320] = _T("WM_DWMCOLORIZATIONCOLORCHANGED");
		wm[0x0321] = _T("WM_DWMWINDOWMAXIMIZEDCHANGE");
		wm[0x033F] = _T("WM_GETTITLEBARINFOEX");
		wm[0x0358] = _T("WM_HANDHELDFIRST");
		wm[0x035F] = _T("WM_HANDHELDLAST");
		wm[0x0360] = _T("WM_AFXFIRST");
		wm[0x037F] = _T("WM_AFXLAST");
		wm[0x0380] = _T("WM_PENWINFIRST");
		wm[0x038F] = _T("WM_PENWINLAST");
		//(0x0360 - 0x037F are reserved for MFC) #include <afxpriv.h>
		wm[0x0360] = _T("WM_QUERYAFXWNDPROC");
		wm[0x0361] = _T("WM_SIZEPARENT");
		wm[0x0362] = _T("WM_SETMESSAGESTRING");
		wm[0x0363] = _T("WM_IDLEUPDATECMDUI");
		wm[0x0364] = _T("WM_INITIALUPDATE");
		wm[0x0365] = _T("WM_COMMANDHELP");
		wm[0x0366] = _T("WM_HELPHITTEST");
		wm[0x0367] = _T("WM_EXITHELPMODE");
		wm[0x0368] = _T("WM_RECALCPARENT");
		wm[0x0369] = _T("WM_SIZECHILD");
		wm[0x036A] = _T("WM_KICKIDLE");
		wm[0x036B] = _T("WM_QUERYCENTERWND");
		wm[0x036C] = _T("WM_DISABLEMODAL");
		wm[0x036D] = _T("WM_FLOATSTATUS");
		wm[0x036E] = _T("WM_ACTIVATETOPLEVEL");
		wm[0x036F] = _T("WM_RESERVED_036F");
		wm[0x0370] = _T("WM_RESERVED_0370");
		wm[0x0371] = _T("WM_RESERVED_0371");
		wm[0x0372] = _T("WM_RESERVED_0372");
		wm[0x0373] = _T("WM_SOCKET_NOTIFY");
		wm[0x0374] = _T("WM_SOCKET_DEAD");
		wm[0x0375] = _T("WM_POPMESSAGESTRING");
		wm[0x0376] = _T("WM_HELPPROMPTADDR");
		wm[0x0376] = _T("WM_OCC_LOADFROMSTREAM");
		wm[0x0377] = _T("WM_OCC_LOADFROMSTORAGE");
		wm[0x0378] = _T("WM_OCC_INITNEW");
		wm[0x0379] = _T("WM_QUEUE_SENTINEL");
		wm[0x037A] = _T("WM_OCC_LOADFROMSTREAM_EX");
		wm[0x037B] = _T("WM_OCC_LOADFROMSTORAGE_EX");
		wm[0x037C] = _T("WM_RESERVED_037C");
		wm[0x037D] = _T("WM_RESERVED_037D");
		wm[0x037E] = _T("WM_RESERVED_037E");
		wm[0x037F] = _T("WM_FORWARDMSG");
		//wm[0x0400] = _T("WM_USER");
		//wm[0x8000] = _T("WM_APP");
		binit = TRUE;
	}
	if (msgCode < 0x0400 && wm[msgCode]) return wm[msgCode];
	else if (msgCode == 0x0400) return _T("WM_USER");
	else if (msgCode == 0x0800) return _T("WM_APP");
	else
	{
		static TCHAR temp[10];
		if (msgCode >> 16) _stprintf_s(temp, 10, _T("_%08X"), msgCode);
		else _stprintf_s(temp, 10, _T("WM_0x%04X"), msgCode);
		return temp;
	}
}

#endif // __CR_DEBUG_OUTPUT_H_
